package com.chenfan.magic.core.executer;

import com.chenfan.magic.base.Kv;
import com.chenfan.magic.base.R;
import com.chenfan.magic.constant.RuntimeConstant;
import com.chenfan.magic.core.IdcEngineEntry;
import com.chenfan.magic.core.MagicLogPublisher;
import com.chenfan.magic.entity.MQLModel;
import com.chenfan.magic.entity.MemoryModel;
import com.chenfan.magic.entity.TTLDetailModel;
import com.chenfan.magic.entity.TTLModel;
import com.chenfan.magic.tags.handler.*;
import com.chenfan.magic.utils.FastJsonKit;
import com.google.common.collect.Maps;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.Iterator;
import java.util.Map;

/**
 * IDC主执行引擎
 *
 * @author caohui
 * <p>
 * 一级加速策略: Redis缓存控制. (待增强).
 * 二级加速策略: mysql直接挂载映射入clickhouse.
 * 三级加速策略: OSC二级缓存框架引入. j2cache.
 */
@Slf4j
@Data
@Component
public class _MainExecuter {

    @Autowired
    private TagRobotHandler tagRobotHandler;

    @Autowired
    private TagEmailHandler tagEmailHandler;

    @Autowired
    private TagSmsHandler tagSmsHandler;

    @Autowired
    private TagResolveHandler tagResolveHandler;

    @Autowired
    private TagValidateHandler tagValidateHandler;

    @Autowired
    private TagTemplateHandler tagTemplateHandler;

    @Autowired
    private TagScriptHandler tagScriptHandler;

    @Autowired
    private TagShellHandler tagShellHandler;

    @Autowired
    private TagRedisHandler tagRedisHandler;

    @Autowired
    private TagHttpHandler tagHttpHandler;

    public R run(String scriptIndex, Map<String, Object> idcRuntimePool, Map<String, Object> paramMap, TTLModel ttlModel) {
        return run(scriptIndex, idcRuntimePool, paramMap, ttlModel, null, false);
    }

    public R run(String scriptIndex, Map<String, Object> idcRuntimePool, Map<String, Object> paramMap, TTLModel ttlModel, boolean debug) {
        return run(scriptIndex, idcRuntimePool, paramMap, ttlModel, null, debug);
    }

    public R run(String scriptIndex, Map<String, Object> idcRuntimePool, Map<String, Object> paramMap, TTLModel ttlModel, MemoryModel memoryModel, boolean debug) {
        TTLDetailModel summaryModel = new TTLDetailModel();
        summaryModel.start("executer#bus");

        //开始解析执行
        MQLModel mqlModel = (MQLModel) idcRuntimePool.get(RuntimeConstant.RUNTIME_MQL);
        R finalResult = R.success();
        Map<String, Object> scopeResult = Maps.newHashMap();
        Map<String, Object> resultSetPool = Maps.newHashMap();
        idcRuntimePool.put(RuntimeConstant.RUNTIME_RESULTSET, resultSetPool);

        Map<String, Object> eofMap = Maps.newHashMap();
        Map<String, Object> resolveMap = Maps.newHashMap();
        Map<String, Object> attributeMap = Maps.newHashMap();
        R responseParamMap = R.success();
        if (debug) {
            responseParamMap.put("runtime_execute_id", idcRuntimePool.get(RuntimeConstant.RUNTIME_ID));
            responseParamMap.put("runtime_constantMap", FastJsonKit.map2Jsonstring((Map<String, Object>) idcRuntimePool.get(RuntimeConstant.RUNTIME_CONSTANTS)));
            responseParamMap.put("runtime_requestParamMap", FastJsonKit.map2Jsonstring((Map<String, Object>) idcRuntimePool.get(RuntimeConstant.RUNTIME_REQUEST_PARAMS)));
            responseParamMap.put("runtime_tokenArrowsMap", FastJsonKit.map2Jsonstring((Map<String, Object>) idcRuntimePool.get(RuntimeConstant.RUNTIME_TOKEN_ARROWS)));
            responseParamMap.put("runtime_scriptObj", FastJsonKit.toJSONString(idcRuntimePool.get(RuntimeConstant.RUNTIME_SCRIPT)));
        }

        Iterator<Map.Entry<String, Integer>> iterator = mqlModel.getSortIdMap().entrySet().iterator();
        try {
            while (iterator.hasNext()) {
                Map.Entry<String, Integer> entry = iterator.next();
                String key = entry.getKey();
                log.info("IDC Engine => Execute " + key);
                Kv kv = Kv.init()
                        .set(RuntimeConstant.RUNTIME_EXECUTE_VAR_KEY_RESPOND, false)
                        .set(RuntimeConstant.RUNTIME_EXECUTE_VAR_KEY_RESULTKEY, "")
                        .set(RuntimeConstant.RUNTIME_EXECUTE_VAR_KEY_PREFIXKEY, "");
                boolean pieceRes = false;
                if (mqlModel.getResolveModelMap().containsKey(key)) {
                    pieceRes = tagResolveHandler.execute(mqlModel, idcRuntimePool, key, paramMap, scopeResult, eofMap, resolveMap, attributeMap, kv, ttlModel);
                } else if (mqlModel.getValidateModelMap().containsKey(key)) {
                    pieceRes = tagValidateHandler.execute(mqlModel, idcRuntimePool, key, paramMap, scopeResult, eofMap, resolveMap, attributeMap, kv, ttlModel);
                } else if (mqlModel.getTemplateModelMap().containsKey(key)) {
                    pieceRes = tagTemplateHandler.execute(mqlModel, idcRuntimePool, key, paramMap, scopeResult, eofMap, resolveMap, attributeMap, kv, ttlModel);
                } else if (mqlModel.getScriptModelMap().containsKey(key)) {
                    pieceRes = tagScriptHandler.execute(mqlModel, idcRuntimePool, key, paramMap, scopeResult, eofMap, resolveMap, attributeMap, kv, ttlModel);
                } else if (mqlModel.getShellModelMap().containsKey(key)) {
                    pieceRes = tagShellHandler.execute(mqlModel, idcRuntimePool, key, paramMap, scopeResult, eofMap, resolveMap, attributeMap, kv, ttlModel);
                } else if (mqlModel.getRedisModelMap().containsKey(key)) {
                    pieceRes = tagRedisHandler.execute(mqlModel, idcRuntimePool, key, paramMap, scopeResult, eofMap, resolveMap, attributeMap, kv, ttlModel);
                } else if (mqlModel.getHttpModelMap().containsKey(key)) {
                    pieceRes = tagHttpHandler.execute(mqlModel, idcRuntimePool, key, paramMap, scopeResult, eofMap, resolveMap, attributeMap, kv, ttlModel);
                } else if (mqlModel.getEmailModelMap().containsKey(key)) {
                    pieceRes = tagEmailHandler.execute(mqlModel, idcRuntimePool, key, paramMap, scopeResult, eofMap, resolveMap, attributeMap, kv, ttlModel);
                } else if (mqlModel.getSmsModelMap().containsKey(key)) {
                    pieceRes = tagSmsHandler.execute(mqlModel, idcRuntimePool, key, paramMap, scopeResult, eofMap, resolveMap, attributeMap, kv, ttlModel);
                } else if (mqlModel.getRobotModelMap().containsKey(key)) {
                    pieceRes = tagRobotHandler.execute(mqlModel, idcRuntimePool, key, paramMap, scopeResult, eofMap, resolveMap, attributeMap, kv, ttlModel);
                } else {
                    break;
                }
                if (!pieceRes) {
                    break;
                }
                Map<String, Object> res = (Map<String, Object>) scopeResult.get(kv.getStr(RuntimeConstant.RUNTIME_EXECUTE_VAR_KEY_PREFIXKEY));
                if (kv.getBool(RuntimeConstant.RUNTIME_EXECUTE_VAR_KEY_RESPOND)) {
                    resultSetPool.putAll(res);
                    idcRuntimePool.put(RuntimeConstant.RUNTIME_RESULTSET, resultSetPool);
                }
                if (!EOFExecuter.run(eofMap, res.get(kv.getStr(RuntimeConstant.RUNTIME_EXECUTE_VAR_KEY_RESULTKEY)) + "", kv.getStr(RuntimeConstant.RUNTIME_EXECUTE_VAR_KEY_PREFIXKEY))) {
                    IdcEngineEntry.throwException(idcRuntimePool, finalResult.getData(), eofMap);
                    return finalResult;
                }
            }

            Map<String, Object> resultSet = (Map<String, Object>) idcRuntimePool.get(RuntimeConstant.RUNTIME_RESULTSET);
            resultSet.remove("#params");
            resultSet.remove("#context");
            responseParamMap.put("runtime_resultSet", FastJsonKit.map2Jsonstring(resultSet))
                    .put("runtime_ttl", FastJsonKit.toJSONString(ttlModel))
                    .put("runtime_scopeResult", FastJsonKit.map2Jsonstring(scopeResult))
                    .put("runtime_resolver", FastJsonKit.map2Jsonstring(resolveMap))
                    .put("runtime_attributes", FastJsonKit.map2Jsonstring(attributeMap));
            if (memoryModel != null) {
                memoryModel.end();
                responseParamMap.put("runtime_memory", FastJsonKit.toJSONString(memoryModel));
            }
            finalResult.putAll((Map<String, Object>) idcRuntimePool.get(RuntimeConstant.RUNTIME_RESULTSET));
            finalResult.putAll(eofMap);
            if (debug) {
                finalResult.put("#runtime", FastJsonKit.map2Jsonstring(responseParamMap.getData()));
            }
            ttlModel.getExecuter().put(summaryModel.end());
            //推送成功日志.
            MagicLogPublisher.publishExecuterSuccessEvent(idcRuntimePool.get(RuntimeConstant.RUNTIME_ID) + "",
                    FastJsonKit.map2Jsonstring(finalResult.getData()),
                    FastJsonKit.map2Jsonstring((Map<String, Object>) idcRuntimePool.get(RuntimeConstant.RUNTIME_RESULTSET)),
                    "");
        } catch (Exception e) {
            e.printStackTrace();
            IdcEngineEntry.throwException(idcRuntimePool, finalResult.getData(), e);
        }
        return finalResult;
    }


}
